﻿/*
 * pb_main.cpp
 *
 *  Created on: 2017年10月31日
 *      Author: work
 */


#include <boost/program_options.hpp>
#include <iostream>
#include <fstream>
#include <dm/protocol/modbusmap.hpp>

using namespace std;
using namespace boost::program_options;

string path2def( const string& p ){
	string r="_";
	for( unsigned int i=0;i<p.size();++i ){
		if( p[i]=='/' || p[i]=='.' )
			r += '_';
		else
			r += p[i];
	}
	r += '_';

	return r;
}

int main( int argc,char* argv[] ){
	options_description desc("【DM2016帮助文档】\n Modbus映射工具。\n\t基于DM2016系统构建\n支持以下选项");

	options_description generic("一般选项");
	generic.add_options()
			("help,h","显示本帮助信息")
			("version,v","显示版本及编译信息")
			;
	desc.add(generic);

	options_description opt_pb("命令参数");
	opt_pb.add_options()
			("config,c",value<string>(),"配置文件")
			("silent,s","静默方式")
			("csv",value<string>(),"产生csv点表目录。比如gen")
			("hpp",value<string>(),"产生点表头文件名.比如gen/plc.hpp");

	desc.add(opt_pb);

	variables_map vm;
	try{
		store(parse_command_line(argc,argv,desc),vm);
		notify(vm);
	}catch( std::exception& ex ){
		cout << ex.what()<<endl;
		return 1;
	}

	if( vm.count("help") ){
		cout <<desc<<endl;
		return 1;
	}

	if( vm.count("version") ){
		cout <<"V1.0 构建于 "<<__DATE__<<endl;
		return 1;
	}

	dm::protocol::CModbusMap map;
	if( !map.init(vm["config"].as<string>().c_str(),!vm.count("silent")) ){
		cout <<"异常退出!"<<endl;
		return -1;
	}

	if( vm.count("csv") ){
		ofstream ostr;
		string file;
		if( map.statuses().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/状态量.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ofstream::trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"#名称;描述;备注;级别;分状态;合状态;无效分状态;无效合状态;是否存盘;是否产生时标数据;是否上报时标数据"<<endl
					<<";;;;;;;;;;"<<endl;

			for( unsigned int i=0;i<map.statuses().size();++i ){
				dm::protocol::CModbusMapStatus* item = map.statuses()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address();
				ostr <<'['<<item->bitOffset()<<','<<item->bitLen()<<"];"
						<<item->level()<<';'
						<<item->offDesc()<<';'
						<<item->onDesc()<<';'
						<<item->invOffDesc()<<';'
						<<item->invOnDesc()<<';';

				ostr <<(item->ifStore()?1:0)<<';'
						<<(item->ifGenTimed()?1:0)<<';'
						<<(item->ifReportTimed()?1:0);

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}

		if( map.discretes().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/离散量.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ostr.trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"#名称;描述;备注;状态1:状态2:...:状态n;是否存盘;是否产生时标数据;是否上报时标数据"<<endl
					<<";;;;;;"<<endl;

			for( unsigned int i=0;i<map.discretes().size();++i ){
				dm::protocol::CModbusMapDiscrete* item = map.discretes()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address();
				ostr <<'['<<item->bitOffset()<<','<<item->bitLen()<<"];";
				if( item->valueDescs().size()==0 ){
					cout <<"错误：离散量没有配置值列表"<<endl;
					return -2;
				}

				ostr <<item->valueDescs()[0];
				for( unsigned int j=1;j<item->valueDescs().size();++j )
					ostr <<':'<<item->valueDescs()[j];
				ostr<<';';


				ostr <<(item->ifStore()?1:0)<<';'
						<<(item->ifGenTimed()?1:0)<<';'
						<<(item->ifReportTimed()?1:0);

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}

		if( map.measures().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/测量量.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ostr.trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"# 名称;描述;备注;单位;变化限值;基数;系数;是否存盘;是否产生时标数据;是否上报时标数据"<<endl
					<<";;;;;;;;;"<<endl;

			for( unsigned int i=0;i<map.measures().size();++i ){
				dm::protocol::CModbusMapMeasure* item = map.measures()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address()<<' ';
				ostr <<item->typeString(item->type())<<';'
						<<item->unit()<<';'
						<<item->delta()<<';'
						<<item->base()<<';'
						<<item->coef()<<';';

				ostr <<(item->ifStore()?1:0)<<';'
						<<(item->ifGenTimed()?1:0)<<';'
						<<(item->ifReportTimed()?1:0);

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}

		if( map.cumulants().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/累计量.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ostr.trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"#名称;描述;备注;满码值;变化限值;系数;是否存盘;是否产生时标数据;是否上报时标数据"<<endl
					<<";;;;;;;;"<<endl;

			for( unsigned int i=0;i<map.cumulants().size();++i ){
				dm::protocol::CModbusMapCumulant* item = map.cumulants()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address()<<' ';
				ostr <<item->typeString(item->type())<<';'
						<<item->maxCode()<<';'
						<<item->delta()<<';'
						<<item->coef()<<';';

				ostr <<(item->ifStore()?1:0)<<';'
						<<(item->ifGenTimed()?1:0)<<';'
						<<(item->ifReportTimed()?1:0);

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}

		if( map.parameters().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/参数.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ostr.trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"#名称;描述;备注"<<endl
					<<";;"<<endl;

			for( unsigned int i=0;i<map.parameters().size();++i ){
				dm::protocol::CModbusMapParameter* item = map.parameters()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address()<<' ';
				ostr <<item->typeString(item->type());

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}

		if( map.rmtctls().size()>0 ){
			file = vm["csv"].as<string>();
			file += "/远控.csv";

			cout <<"\n产生点表 "<<file<<"...";
			ostr.open(file.c_str(),ostr.trunc);
			if( !ostr.is_open() ){
				cout <<"打开文件失败!"<<endl;
				return -2;
			}

			ostr<<"# 本文件由Modbus映射工具产生。不用归档保存"<<endl
					<<"#名称;描述;备注;测试;复位;控分;控合"<<endl
					<<";;;;;;"<<endl;

			for( unsigned int i=0;i<map.rmtctls().size();++i ){
				dm::protocol::CModbusMapRmtctl* item = map.rmtctls()[i];

				ostr <<item->name()<<';'
						<<item->desc()<<';'
						<<item->fun()<<'x'<<item->address();
				ostr <<'['<<item->bitOffset()<<','<<item->bitLen()<<"];"
						<<item->preOpenDesc()<<';'
						<<item->preCloseDesc()<<';'
						<<item->openDesc()<<';'
						<<item->closeDesc();

				ostr <<endl;
			}

			ostr <<"#结束"<<endl;
			ostr.close();
			cout <<" 成功";
		}
	}

	if( vm.count("hpp") ){
		ofstream ostr;
		string file =vm["hpp"].as<string>();

		cout <<"\n产生C++头文件 "<<file<<"...";
		ostr.open(file.c_str(),ostr.trunc);
		if( !ostr.is_open() ){
			cout <<"打开文件失败!"<<endl;
			return -2;
		}

		string d = path2def(file);
		ostr <<"/*\n"
				<<" 本文件有Modbus映射工具自动产生，请勿手动修改\n"
				<<"*/"<<endl;
		ostr <<"#ifndef "<<d<<endl
				<<"#define "<<d<<endl<<endl
				<<"class C"+d+"{"<<endl
				<<"public:"<<endl;

		if( map.statuses().size()>0 ){
			cout <<"\n增加状态量定义...";
			ostr <<"\tenum EStatus{\n";

			for( unsigned int i=0;i<map.statuses().size();++i ){
				ostr <<"\t\tS"+map.statuses()[i]->name()<<",\t// "<<map.statuses()[i]->desc()<<endl;
			}

			ostr <<"\t\tSMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		if( map.discretes().size()>0 ){
			cout <<"\n增加离散量定义...";
			ostr <<"\tenum EDiscrete{\n";

			for( unsigned int i=0;i<map.discretes().size();++i ){
				ostr <<"\t\tD"+map.discretes()[i]->name()<<",\t// "<<map.discretes()[i]->desc()<<endl;
			}

			ostr <<"\t\tDMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		if( map.measures().size()>0 ){
			cout <<"\n增加测量量定义...";
			ostr <<"\tenum EMeasure{\n";

			for( unsigned int i=0;i<map.measures().size();++i ){
				ostr <<"\t\tM"+map.measures()[i]->name()<<",\t// "<<map.measures()[i]->desc()<<endl;
			}

			ostr <<"\t\tMMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		if( map.cumulants().size()>0 ){
			cout <<"\n增加累计量定义...";
			ostr <<"\tenum ECumulant{\n";

			for( unsigned int i=0;i<map.cumulants().size();++i ){
				ostr <<"\t\tC"+map.cumulants()[i]->name()<<",\t// "<<map.cumulants()[i]->desc()<<endl;
			}

			ostr <<"\t\tCMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		if( map.rmtctls().size()>0 ){
			cout <<"\n增加远控定义...";
			ostr <<"\tenum ERmtctl{\n";

			for( unsigned int i=0;i<map.rmtctls().size();++i ){
				ostr <<"\t\tR"+map.rmtctls()[i]->name()<<",\t// "<<map.rmtctls()[i]->desc()<<endl;
			}

			ostr <<"\t\tRMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		if( map.parameters().size()>0 ){
			cout <<"\n增加参数定义...";
			ostr <<"\tenum EParam{\n";

			for( unsigned int i=0;i<map.parameters().size();++i ){
				ostr <<"\t\tP"+map.parameters()[i]->name()<<",\t// "<<map.parameters()[i]->desc()<<endl;
			}

			ostr <<"\t\tPMax"<<endl
					<<"\t};"<<endl;
			cout <<" 成功";
		}

		ostr <<"}\n"
				<<"#endif"<<endl;

		cout <<"\n成功"<<endl;
	}

	cout <<endl;
	return 0;
}
